//
//  MolonAPI.m
//
//  Created by Molon on 13-10-4.
//  Copyright (c) 2013年 Molon. All rights reserved.
//

#import "MolonAPI.h"
#import "MLDataHelper.h"
#import "NSString+MLKit.h"
#import "MLKitDebug.h"
#import "NSMutableURLRequest+MolonAPI.h"
#import "NSObject+MolonAPI.h"
#import "MLSecurity.h"
#import "MLUUID.h"
#import "MLRequestCache.h"
#import "MolonRequestHelper.h"
#import "MLKitDefine.h"


#define kUserDefaultKeyForSessionID @"com.molon.molonapi.sessionid"

NSString * const MolonAPIRequestHelperStateUpdatedNotificationNamePrefix = @"com.molon.molonAPI.requestHelperStateUpdated.";

@implementation ServiceURL

- (void)setRequestMethod:(NSString *)requestMethod
{
    NSAssert(([@[@"POST",@"GET",@"PUT",@"DELETE"]containsObject:requestMethod]), @"%@请求方式只能是POST,GET,PUT,DELETE其中一个",self.url);
    _requestMethod = [requestMethod copy];
}

@end


@interface MolonAPI ()

/**
 *  sessionID,有值代表已经登录
 */
@property (nonatomic, copy) NSString *sessionID;

/**
 *  项目中ServiceURL集合
 */
@property (nonatomic, strong) NSMutableDictionary *apiServiceUrls;
/**
 *  需要在登录后重试的请求集合 {@"requestHelper":xxx,@"bindObject":xxx}
 */
@property (nonatomic, strong) NSMutableArray *needRetryHelpersAfterLogin;

/**
 *  需要取消的发生请求，用来对应安全忽略的临时存储罢了
 */
@property (nonatomic, strong) NSMutableArray *needCancelOperations;

@end

@implementation MolonAPI

+ (instancetype)sharedInstance {
    static MolonAPI *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self class] new];
    });
    return _sharedInstance;
}

#pragma mark - init
- (void)setUpDefaultConfig
{
    self.requestCacheOn = YES;
    self.sessionKey = @"session";
    self.apiVersionKey = @"";
    self.deviceIDKey = @"";
    self.osTagKey = @"";
    self.appVersionKey = @"";
    
    self.apiVersion = @"1.0";
    self.md5SignOn = NO;
    self.md5SignKey = @"sign";
    self.md5SignSecret = @"molon";
    self.requestTimeoutInterval = 10.0f;
    self.uploadTimeoutInterval = 120.0f;
}

- (instancetype)init {
    //初始化
    self = [super init];
    if (self) {
        [self setUpDefaultConfig];
        //设置cookie是一直接受，其实我们session以URL里传递为主
        //但如果在没登录时候吧，如果客户端不记录cookie(用以记录sessionID)的话，在未登录状态下服务端总是会生成新的session文件的。
        //而如果在登录后，我们会一直在URL里指定sessionID了。服务端就会以这个ID为准了。
        //服务端需要这样做才OK。
        [[NSHTTPCookieStorage sharedHTTPCookieStorage]setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
        
        NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
        self.sessionID = [userDefault objectForKey:kUserDefaultKeyForSessionID];
        
        //设置解释器
        self.responseSerializer = [AFJSONResponseSerializer serializer];
        //        self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", nil];
        
    }
    return self;
}

#pragma mark - setter
- (void)setDelegate:(id<MolonAPIDelegate>)delegate
{
    _delegate = delegate;
    
    //设置好hostName
    NSMutableDictionary *serviceAPIMap = [NSMutableDictionary dictionaryWithContentsOfFile:[self.delegate apiMapPlistPath]];
    
    NSAssert(serviceAPIMap, @"使用MolonAPI必须设置对应的接口地图文件");
    
#ifdef DEBUG
    NSString *commonHostName = [MLDataHelper getStringValue:serviceAPIMap[@"DevelopmentHostName"] defaultValue:nil];
#else
    NSString *commonHostName = [MLDataHelper getStringValue:serviceAPIMap[@"DistributionHostName"] defaultValue:nil];
#endif
    NSAssert(commonHostName, @"必须为MolonAPI提供主机名字HostName");
    self.hostName = commonHostName;
}

- (void)setRequestTimeoutInterval:(double)requestTimeoutInterval
{
    _requestTimeoutInterval = requestTimeoutInterval;
    //并发值如果太高，会引起一群请求下的很多超时产生，这里需要限制下并发数，取一个差不多合适的值
    self.operationQueue.maxConcurrentOperationCount = MAX(1, (NSInteger)(floor(requestTimeoutInterval/3)));
}

- (void)setHostName:(NSString *)untidyhostName
{
    NSAssert(self.delegate, @"MolonAPI必须设置delegate");
    
    NSString *oldHostName = _hostName;
    NSString *newHostName = [self hostNameAfterAdjustWithHostName:untidyhostName];
    if ([oldHostName isEqualToString:newHostName]) {
        //重复不用管他
        return;
    }
    
    _hostName = [newHostName copy];
    
    NSMutableDictionary *serviceAPIMap = [NSMutableDictionary dictionaryWithContentsOfFile:[self.delegate apiMapPlistPath]];
    
    self.apiServiceUrls = [NSMutableDictionary dictionary];
    
    NSDictionary *apiMap = [MLDataHelper getDictionaryValue:serviceAPIMap[@"APIMap"] defaultValue:nil];
    for (NSString *methodName in [apiMap allKeys]) {
        NSMutableDictionary *attributes = [MLDataHelper getDictionaryValue:apiMap[methodName] defaultValue:nil];
        
        ServiceURL *serviceUrl = [[ServiceURL alloc] init];
        NSString *hostName = [self hostNameAfterAdjustWithHostName:[MLDataHelper getStringValue:attributes[@"CustomHostName"] defaultValue:nil]];
        
        if ([NSString IsNilOrEmpty:hostName]) {
            hostName = self.hostName;
        }
        //设置其URL
        NSString *suffix =  [methodName hasPrefix:@"/"]?[methodName substringFromIndex:1]:methodName;
        serviceUrl.url = [NSString stringWithFormat:@"%@%@",hostName,suffix];
        
        serviceUrl.isNeedLogin = [MLDataHelper getBoolValue:attributes[@"IsNeedLogin"]
                                               defaultValue:NO];
        serviceUrl.requestMethod = [[MLDataHelper getStringValue:attributes[@"RequestMethod"] defaultValue:@"POST"]trimString];
        
        if (self.delegate&&[self.delegate respondsToSelector:@selector(doCustomWithServiceUrl:)]) {
            [self.delegate doCustomWithServiceUrl:serviceUrl];
        }
        
        self.apiServiceUrls[methodName] = serviceUrl;
    }
}

- (void)setSessionID:(NSString *)sessionID
{
    _sessionID = [sessionID copy];
    
    //本地存储记录起来
    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    if (![NSString IsNilOrEmpty:sessionID]) {
        [userDefault setObject:sessionID forKey:kUserDefaultKeyForSessionID];
    }else{
        [userDefault removeObjectForKey:kUserDefaultKeyForSessionID];
    }
    [userDefault synchronize];
}

#pragma mark - getter
- (NSMutableArray *)needRetryHelpersAfterLogin
{
    if (!_needRetryHelpersAfterLogin) {
        _needRetryHelpersAfterLogin = [NSMutableArray array];
    }
    return _needRetryHelpersAfterLogin;
}

- (NSMutableArray *)needCancelOperations
{
    if (!_needCancelOperations) {
        _needCancelOperations = [NSMutableArray array];
    }
    return _needCancelOperations;
}

#pragma mark - request
+ (void)requestWithHelper:(MolonRequestHelper *)requestHelper andBindObject:(id)bindObject{
    [[self class] requestWithHelper:requestHelper andBindObject:bindObject uploadProgressBlock:nil];
}

+ (void)requestWithHelper:(MolonRequestHelper *)requestHelper andBindObject:(id)bindObject uploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))uploadBlock {
    [[[self class] sharedInstance] sendRequestWithHelper:requestHelper andBindObject:bindObject uploadProgressBlock:uploadBlock cantReRequest:YES];
}

+ (void)cancelRequestHelper:(MolonRequestHelper*)requestHelper
{
    [[[self class] sharedInstance] cancelRequestHelper:requestHelper];
}

+ (void)clearRetryHelpersAfterLogin
{
    [[MolonAPI sharedInstance].needRetryHelpersAfterLogin removeAllObjects];
}

#pragma mark - common
/**
 *  sessionID置空
 */
- (void)emptySessionID
{
    self.sessionID = nil;
}

/**
 *  因为某请求引起的登录
 */
- (void)gotoLoginBecauseHelper:(MolonRequestHelper*)helper andBindObject:(id)bindObject
{
    NSAssert(![helper isKindOfClass:[self.delegate LoginRequestHelperClass]], @"登录接口不能返回没登录的erroCode");
    
#ifdef DEBUG
    ServiceURL *serviceUrl = self.apiServiceUrls[helper.methodName];
    if (!serviceUrl.isNeedLogin) {
        DLOG(@"发现需登录但客户端未标记的请求%@",helper);
    }
#endif
    
    [self emptySessionID];
    
    //将问题helper添加到重试数组里
    NSDictionary *aRetryRecord;
    if (bindObject) {
        aRetryRecord = @{@"requestHelper":helper,@"bindObject":bindObject};
    }else{
        aRetryRecord = @{@"requestHelper":helper};
    }
    [self.needRetryHelpersAfterLogin addObject:aRetryRecord];
    
    //只有第一次引起去登录事件才会触发delegate方法
//    if (self.needRetryHelpersAfterLogin.count==1) {
        [self.delegate gotoLogin];
//    }
    
    //停止所有标记为需要登录的请求
    for (AFHTTPRequestOperation *aOperation in self.operationQueue.operations) {
        if ([self.needCancelOperations containsObject:aOperation]) {
            continue;
        }
        
        NSDictionary *userInfo = ((NSMutableURLRequest *)aOperation.request).userInfo;
        MolonRequestHelper *aRequestHelper = userInfo[@"requestHelper"];
        ServiceURL *serviceUrl = self.apiServiceUrls[aRequestHelper.methodName];
        if (serviceUrl.isNeedLogin) {
            //加到重试记录组里，并取消
            [self.needRetryHelpersAfterLogin addObject:userInfo];
            [self.needCancelOperations addObject:aOperation];
            [aOperation cancel];
        }
    }
}

/**
 *  在登录完成之后重试这些请求
 */
- (void)retryRecordedHelpersAfterLogin
{
    [self.needCancelOperations removeAllObjects];
    if ([self needRetryRequestHelpersAfterLogin]) {
        for (NSDictionary *aRetryRecord in self.needRetryHelpersAfterLogin) {
#warning dont support retry upload block
            [[MolonAPI sharedInstance]sendRequestWithHelper:aRetryRecord[@"requestHelper"] andBindObject:aRetryRecord[@"bindObject"] uploadProgressBlock:nil cantReRequest:NO];
        }
    }
    [self.needRetryHelpersAfterLogin removeAllObjects];//清空所有
}

- (BOOL)needRetryRequestHelpersAfterLogin
{
    BOOL needRetry = YES;
    if (self.delegate&&[self.delegate respondsToSelector:@selector(needRetryRequestHelpersAfterLogin)]) {
        needRetry = [self.delegate needRetryRequestHelpersAfterLogin];
    }
    return needRetry;
}

- (BOOL)isLogined
{
    return ![NSString IsNilOrEmpty:self.sessionID];
}

+ (BOOL)isLogined
{
    return [[[self class]sharedInstance]isLogined];
}

#pragma mark - send request
- (void)sendRequestWithHelper:(MolonRequestHelper *)requestHelper andBindObject:(id)bindObject uploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))uploadBlock cantReRequest:(BOOL)cantReRequest
{
    NSAssert(self.delegate, @"MolonAPI必须设置delegate");
    NSAssert(requestHelper, @"requestHelper不可为nil");
    NSAssert((cantReRequest&&requestHelper.state != MolonRequestHelperStateRequesting)||(!cantReRequest), @"请求%@正在进行中，不可重复send",requestHelper);
    
    requestHelper.isCurrentPreloaded = NO;
    requestHelper.state = MolonRequestHelperStateRequesting;
    requestHelper.error = nil;
    
    //投递一个关于helper的开始通知，关心者添加即可
    [self postUpdatedNotificationForRequestHelper:requestHelper andBindObject:bindObject];
    
    //获取请求的一些属性
    ServiceURL *serviceUrl = self.apiServiceUrls[requestHelper.methodName];
    NSAssert(serviceUrl, @"请求%@的相应记录不存在",requestHelper.methodName);
    
    //判断是否需要登录
    if (serviceUrl.isNeedLogin) {
        if (![self isLogined]) {
            [self gotoLoginBecauseHelper:requestHelper andBindObject:bindObject];
            //如果不需要重试请求，这里应该需要返回错误信息才对
            if (![self needRetryRequestHelpersAfterLogin]) {
                //失败了
                NSDictionary *error = @{@"message":@"",@"error":@([self.delegate notLoginErrorCode])};
                
                dispatch_async(dispatch_get_main_queue(), ^{
                    requestHelper.error = error;
                    requestHelper.state = MolonRequestHelperStateRequestFailed;
                    
                    //执行对应的requestFailed
                    if (bindObject) {
                        [bindObject ml_nsobject_requestFailed:requestHelper];
                    }
                    [self postUpdatedNotificationForRequestHelper:requestHelper andBindObject:bindObject];
                });
            }
            return;
        }
    }
    
    //在发送之前做些操作，例如对一些参数的再处理和默认赋值之类的
    [requestHelper doSomethingBeforeSend];
    
    //构造参数
    NSMutableDictionary *parameters = [requestHelper getRequestParams];
    
    //添加些其他参数，系统级的。session啊 version啊 ostag之类的
    [self putStaticParametersWithRequestParameters:parameters];
    
#ifdef DEBUG
    void(^debugOuputMessage)(BOOL useCache) = ^(BOOL useCache){
        NSString *getPars = [serviceUrl.url stringByAppendingString:@"?"];
        for (NSString *key in [parameters allKeys]) {
            getPars = [getPars stringByAppendingFormat:@"%@=%@&",key,parameters[key]];
        }
        getPars = [getPars substringToIndex:getPars.length-1];
        NSString *useCacheText = useCache?@"(useCache)":@"";
        if (parameters.count>0) {
            DLOG(@"%@\nURL%@:\n%@\n\nParameters:%@",serviceUrl.requestMethod,useCacheText,getPars,parameters);
        }else{
            DLOG(@"%@\nURL%@:\n%@\n",serviceUrl.requestMethod,useCacheText,getPars);
        }
    };
#endif
    
    BOOL isCacheOn = YES;
#ifdef DEBUG
    isCacheOn = self.requestCacheOn;
#endif
    
    if (isCacheOn) {
        //有关cache
        MolonRequestHelperCacheType cacheType = requestHelper.cacheType;
        if (cacheType!=MolonRequestHelperCacheTypeNoCache) {
            NSAssert([requestHelper getRequestFiles].count<=0, @"useCache不可用于上传文件请求里");
            
            requestHelper.cacheFilePath = [MLRequestCache cacheFilePathWithURL:serviceUrl.url andRequestParameters:parameters];
            
            MLRequestCacheState cacheState = [MLRequestCache stateForCacheFilePath:requestHelper.cacheFilePath andValidTime:[requestHelper cacheValidTime]];
            
            if (cacheType == MolonRequestHelperCacheTypeReturnValidCacheElseRequest) {
                if (cacheState==MLRequestCacheStateValid) {
                    //只有缓存完全有效的时候才直接返回
                    id responseObject = [MLRequestCache responseObjectWithCacheFilePath:requestHelper.cacheFilePath];
                    if (responseObject) {
#ifdef DEBUG
                        debugOuputMessage(YES);
#endif
                        //直接成功
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [self requestFinishedWithRequestHelper:requestHelper bindObject:bindObject responseObject:responseObject isResponseCache:YES isPreload:NO];
                        });
                        return;
                    }
                }
            }else if (cacheType == MolonRequestHelperCacheTypeFirstReturnInvalidCacheAndRequest||cacheType == MolonRequestHelperCacheTypeFirstReturnCacheAndAlwaysRequest) {
                if (cacheState!=MLRequestCacheStateNotExisted) {
                    //缓存只要存在，无论过期，都先预加载，然后判断缓存type决定是否继续
                    id responseObject = [MLRequestCache responseObjectWithCacheFilePath:requestHelper.cacheFilePath];
                    if (responseObject) {
                        BOOL isPreload = YES;
                        if (cacheType == MolonRequestHelperCacheTypeFirstReturnInvalidCacheAndRequest) {
                            isPreload = (cacheState==MLRequestCacheStateExpired);
                        }
                        
#ifdef DEBUG
                        if (isPreload) {
                            DLOG(@"预加载");
                        }
                        debugOuputMessage(YES);
#endif
                        
                        //直接成功还是预加载
//                        dispatch_async(dispatch_get_main_queue(), ^{
                            [self requestFinishedWithRequestHelper:requestHelper bindObject:bindObject responseObject:responseObject isResponseCache:YES isPreload:isPreload];
//                        });
                        
                        if (!isPreload) {
                            return;
                        }
                    }
                }
            }
        }
    }
    
    //添加类似时间戳的动态的参数，还有md5签名
    [self putDynamicParametersAndSignWithRequestParameters:parameters];
    if ([self.delegate respondsToSelector:@selector(customAfterCreatingRequestParams:)]) {
        [self.delegate customAfterCreatingRequestParams:parameters];
    }
    
#ifdef DEBUG
    debugOuputMessage(NO);
#endif
    
    //构造请求
    NSError *error = nil;
    NSMutableDictionary *files = [requestHelper getRequestFiles];
    NSMutableURLRequest *request = nil;
    if (files.count>0) {
        NSAssert([serviceUrl.requestMethod isEqualToString:@"POST"]||[serviceUrl.requestMethod isEqualToString:@"HEAD"], @"上传只支持POST和HEAD两种请求方式");
        request = [self.requestSerializer multipartFormRequestWithMethod:serviceUrl.requestMethod URLString:serviceUrl.url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            for (NSString *fileKey in [files allKeys]) {
                [formData appendPartWithFileURL:files[fileKey] name:fileKey fileName:[((NSURL*)files[fileKey]) absoluteString] mimeType:@"application/octet-stream" error:nil];
            }
        } error:&error];
    }else{
        request = [self.requestSerializer requestWithMethod:serviceUrl.requestMethod URLString:serviceUrl.url parameters:parameters error:&error];
    }
    
    NSAssert(request&&!error, @"建立请求错误:%@",error);
    
    NSTimeInterval customTimeoutInterval = [requestHelper customTimeoutInterval];
    if (customTimeoutInterval>0) {
        [request setTimeoutInterval:customTimeoutInterval];
    }else{
        if (files.count>0) {
            [request setTimeoutInterval:self.uploadTimeoutInterval];
        }else{
            [request setTimeoutInterval:self.requestTimeoutInterval];
        }
    }
    
    
    request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    
    //记录helper以便于返回结果的分析
    if (bindObject) {
        request.userInfo = @{@"requestHelper":requestHelper,@"bindObject":bindObject};
    }else{
        request.userInfo = @{@"requestHelper":requestHelper};
    }
    
    //发送请求
    __weak __typeof(self)weakSelf = self;
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf requestFinished:operation responseObject:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf requestError:operation error:error];
    }];
    
    if (uploadBlock) {
        [operation setUploadProgressBlock:uploadBlock];
    }
    
    [self.operationQueue addOperation:operation];
}

- (void)cancelRequestHelper:(MolonRequestHelper*)requestHelper
{
    //如果不是在请求中，没必要继续
    if (requestHelper.state!=MolonRequestHelperStateRequesting) {
        return;
    }
    
    //停止此请求
    for (AFHTTPRequestOperation *aOperation in self.operationQueue.operations) {
        if ([self.needCancelOperations containsObject:aOperation]) {
            continue;
        }
        
        NSDictionary *userInfo = ((NSMutableURLRequest *)aOperation.request).userInfo;
        MolonRequestHelper *aRequestHelper = userInfo[@"requestHelper"];
        if ([aRequestHelper isEqual:requestHelper]) {
            //还原状态
            requestHelper.isCurrentPreloaded = NO;
            requestHelper.state = MolonRequestHelperStateUnRequest;
            
            //标记停止此请求
            [self.needCancelOperations addObject:aOperation];
            [aOperation cancel];
        }
    }
}

#pragma mark - request's result
- (void)requestFinished:(AFHTTPRequestOperation *)operation responseObject:(id)responseObject{
    //这时候[[self operationQueue]operations]已经把operation移除了
    if ([self.needCancelOperations containsObject:operation]) { //这里用来防止意外
        [self.needCancelOperations removeObject:operation];
        
        if ([self needRetryRequestHelpersAfterLogin]) {
            return;
        }
    }
    
    NSDictionary *userInfo = ((NSMutableURLRequest *)operation.request).userInfo;
    MolonRequestHelper *requestHelper = userInfo[@"requestHelper"];
    id bindObject = userInfo[@"bindObject"];
    
    //	DLOG(@"requestFinished - statusCode:%ld", [operation.response statusCode]);
    
    [self requestFinishedWithRequestHelper:requestHelper bindObject:bindObject responseObject:responseObject isResponseCache:NO isPreload:NO];
}

- (void)requestFinishedWithRequestHelper:(MolonRequestHelper*)requestHelper bindObject:(id)bindObject responseObject:(id)responseObject isResponseCache:(BOOL)isResponseCache isPreload:(BOOL)isPreload
{
    BOOL postCare = NO; //是否需要投递care通知
    
    //记录原始数据
    requestHelper.responseData = responseObject;
    
    //获取操作结果res字典
    BOOL isSuccess = [self.delegate isSuccessWithResponseObject:responseObject];
    
    if (!isSuccess) {
        NSAssert(!isPreload, @"预加载数据不可能为fail");
        
        //失败了
        NSDictionary *error = [self.delegate errorWithResponseObject:responseObject];
        NSAssert(error&&error[@"code"], @"请求%@的结果错误集异常",requestHelper);
        
        requestHelper.error = error;
        
        if ([error[@"code"] integerValue]==[self.delegate notLoginErrorCode]) {
            //去登录
            [self gotoLoginBecauseHelper:requestHelper andBindObject:bindObject];
        }
        if ([error[@"code"] integerValue]!=[self.delegate notLoginErrorCode]||![self needRetryRequestHelpersAfterLogin]) {
            requestHelper.state = MolonRequestHelperStateRequestFailed;
            
            //执行对应的requestFailed
            if (bindObject) {
                [bindObject ml_nsobject_requestFailed:requestHelper];
            }
            postCare = YES;
        }
    }else{
        if (!isResponseCache) {
            //缓存数据,只要不是不需要缓存的type，就一直缓存
            if (requestHelper.cacheType!=MolonRequestHelperCacheTypeNoCache) {
                //缓存结果
                [MLRequestCache cacheResponseObject:responseObject toCacheFilePath:requestHelper.cacheFilePath];
            }
        }
        
        //成功了
        id result = [self.delegate successResultDataWithResponseObject:responseObject];
        NSAssert(result, @"请求%@成功，但是没有返回result",requestHelper);
        
        if (requestHelper.tidyResultWithSuccessResultBlock) {
            result = requestHelper.tidyResultWithSuccessResultBlock(result,requestHelper);
        }
        
        // 处理成功后相应的数据解析
        if (requestHelper.customHandResponseDataWithSuccessResultBlock) {
            requestHelper.customHandResponseDataWithSuccessResultBlock(result,requestHelper);
        }else{
            if ([result isKindOfClass:[NSDictionary class]]) {
                [requestHelper handleResponseDataWithDictionary:[MLDataHelper getDictionaryValue:result defaultValue:nil]];
            }else if ([result isKindOfClass:[NSArray class]]){
                [requestHelper handleResponseDataWithArray:[MLDataHelper getArrayValue:result defaultValue:nil]];
            }
        }
        
        if (isPreload) {
            NSAssert(![requestHelper isKindOfClass:[self.delegate LoginRequestHelperClass]]&&![requestHelper isKindOfClass:[self.delegate LogoutRequestHelperClass]], @"登录和注销接口不可预加载！");
            
            requestHelper.isCurrentPreloaded = YES;
            
            [requestHelper doSomethingAfterCachePreloaded];
            //仍然在请求中，需要投递告诉外界
            requestHelper.state = MolonRequestHelperStateRequesting; //这里重新设置下是为了如果有KVO的能捕获到
            
            //执行bindObject的预加载callback
            if (bindObject) {
                [bindObject ml_nsobject_cachePreloaded:requestHelper];
            }
            postCare = YES;
        }else{
            //请求helper可以进一步修改
            [requestHelper doSomethingAfterRequestSuccess];
            requestHelper.state = MolonRequestHelperStateRequestSuccess;
            
            //是登录的接口
            if ([requestHelper isKindOfClass:[self.delegate LoginRequestHelperClass]]) {
                NSAssert(![NSString IsNilOrEmpty:result[self.sessionKey]], @"登录接口必须有返回%@",self.sessionKey);
                self.sessionID = result[self.sessionKey];
                
                if ([self.delegate respondsToSelector:@selector(doAfterLoginSuccessWithHelper:)]) {
                    //检测是登录helper执行OK，则做登录后处理
                    [self.delegate doAfterLoginSuccessWithHelper:requestHelper];
                }
                
                //重试记录helpers
                if ([self isLogined]) {
                    [self retryRecordedHelpersAfterLogin];
                }
            }else if ([requestHelper isKindOfClass:[self.delegate LogoutRequestHelperClass]]){
                //注销的接口
                [self emptySessionID];
                
                if ([self.delegate respondsToSelector:@selector(doAfterLogoutSuccessWithHelper:)]) {
                    [self.delegate doAfterLogoutSuccessWithHelper:requestHelper];
                }
            }
            
            //执行对应的requestSucceeded
            if (bindObject) {
                [bindObject ml_nsobject_requestSucceeded:requestHelper];
            }
            postCare = YES;
        }
    }
    
    //投递一个关于helper的结束通知，关心者添加即可
    if (postCare) {
        [self postUpdatedNotificationForRequestHelper:requestHelper andBindObject:bindObject];
    }
}

- (void)requestError:(AFHTTPRequestOperation *)operation error:(NSError*)error {
    //这时候[[self operationQueue]operations]已经把operation移除了,所以安心remove
    if ([self.needCancelOperations containsObject:operation]) {
        [self.needCancelOperations removeObject:operation];
        
        if ([self needRetryRequestHelpersAfterLogin]) {
            return;
        }
    }
    
    if (error.code==NSURLErrorCancelled) { //取消了的话就不管他
        return;
    }
    
    NSDictionary *userInfo = ((NSMutableURLRequest *)operation.request).userInfo;
    MolonRequestHelper *requestHelper = userInfo[@"requestHelper"];
    id bindObject = userInfo[@"bindObject"];
    
    DLOG(@"requestFailed - statusCode:%ld error:\n%@", (long)[operation.response statusCode],error);
    
    NSMutableDictionary *errorDict = [NSMutableDictionary dictionary];
    
    [errorDict setValue:@(error.code) forKey:@"code"];
    [errorDict setValue:@([operation.response statusCode]) forKey:@"statusCode"];
    
    if (![NSString IsNilOrEmpty:error.userInfo[NSLocalizedDescriptionKey]]) {
        [errorDict setValue:error.userInfo[NSLocalizedDescriptionKey] forKey:@"message"];
    }
    
    requestHelper.error = errorDict;
    requestHelper.state = MolonRequestHelperStateRequestError;
    
    if (bindObject) {
        [bindObject ml_nsobject_requestError:requestHelper];
    }
    
    //投递一个关于helper的结束通知，关心者添加即可
    [self postUpdatedNotificationForRequestHelper:requestHelper andBindObject:bindObject];
}

#pragma mark - private helper
- (NSString*)hostNameAfterAdjustWithHostName:(NSString*)hostName
{
    //hostName进来的会是一个副本
    if (![NSString IsNilOrEmpty:hostName]){
        if (![hostName hasPrefix:@"http://"]) {
            hostName = [NSString stringWithFormat:@"http://%@",hostName];
        }
        if (![hostName hasSuffix:@"/"]) {
            hostName = [hostName stringByAppendingString:@"/"];
        }
    }
    return hostName;
}

//添加
- (void)putStaticParametersWithRequestParameters:(NSMutableDictionary*)parameters
{
    if (self.delegate&&[self.delegate respondsToSelector:@selector(otherSystemParameters)]) {
        [parameters addEntriesFromDictionary:[self.delegate otherSystemParameters]];
    }
    
    //需要添加sessionID参数等系统参数
    if ([self isLogined]) {
        parameters[self.sessionKey] = self.sessionID;
    }
    
    //api版本号
    if (![NSString IsNilOrEmpty:self.apiVersionKey]) {
        parameters[self.apiVersionKey] = self.apiVersion;
    }
    
    //deviceID
    if (![NSString IsNilOrEmpty:self.deviceIDKey]) {
        parameters[self.deviceIDKey] = [MLUUID UUID];
    }
    
    //osTag
    if (![NSString IsNilOrEmpty:self.osTagKey]) {
        parameters[self.osTagKey] = [NSString stringWithFormat:@"iOS%@",[[UIDevice currentDevice] systemVersion]];
    }
    
    if (![NSString IsNilOrEmpty:self.appVersionKey]) {
        parameters[self.appVersionKey] = APP_VERSION;
    }
}

- (void)putDynamicParametersAndSignWithRequestParameters:(NSMutableDictionary*)parameters
{
    //签名
    if (self.md5SignOn&&parameters.count>0) {
        // 按字典顺序将key排序(区分大小写)
        NSArray *sortedArray = [[parameters allKeys] sortedArrayUsingSelector:@selector(compare:)];
        
        // 按Key1Value1Key2Value2Key3Value3....的顺序将所有的键值按顺序拼接成一个字符串
        NSMutableString *query= [[NSMutableString alloc] init];
        for (NSString *key in sortedArray)
        {
            NSString *value = [parameters[key] description];
            [query appendString:key];
            if (![NSString IsNilOrEmpty:value]) {
                [query appendString:value];
            }
        }
        //在该字符串末尾加上app_secret
        [query appendString:self.md5SignSecret];
        
        if (![NSString IsNilOrEmpty:query]) {
            //计算该拼接字符串的md5值(小写)
            NSString *md5Sign = [[MLSecurity md5String:[query lowercaseString]]lowercaseString];
            parameters[self.md5SignKey] = md5Sign;
        }
    }
}


- (void)postUpdatedNotificationForRequestHelper:(MolonRequestHelper*)requestHelper andBindObject:(id)bindObject
{
    NSDictionary *userInfo = nil;
    if (bindObject) {
        userInfo = @{@"requestHelper":requestHelper,@"bindObject":bindObject};
    }else{
        userInfo = @{@"requestHelper":requestHelper};
    }
    [[NSNotificationCenter defaultCenter]postNotificationName:[NSString stringWithFormat:@"%@%@",MolonAPIRequestHelperStateUpdatedNotificationNamePrefix,NSStringFromClass([requestHelper class])] object:nil userInfo:userInfo];
}

@end